using System;
using System.Web;
using System.Web.UI.HtmlControls;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Security.Permissions;
using System.Web.UI.Design;
using System.Text;
using System.Collections.Generic;

namespace Heckel.EasyTools.Diagramming
{
    [ToolboxData("<{0}:DiagramNode runat=server></{0}:DiagramNode>")]
    internal class InternalDiagramNode : CompositeControl, ICallbackEventHandler
    {
        private NodeDetailsEventArgs nodeDoubleClicked;
        private NodeDetailsEventArgs nodeClicked;
        private NodeDetailsEventArgs nodeDeleteClicked;
        
        public virtual int NodeUniqueIdentifier
        {
            get
            {
                if (ViewState["_nodeUniqueIdentifier"] != null)
                {
                    return (int)ViewState["_nodeUniqueIdentifier"];
                }
                else
                {
                    return -1;
                }
            }
            set { ViewState["_nodeUniqueIdentifier"] = value; }
        }

        public virtual int XPos
        {
            get
            {
                if (ViewState["_xPos"] != null)
                {
                    return (int)ViewState["_xPos"];
                }
                else
                {
                    return 0;
                }
            }
            set { ViewState["_xPos"] = value; }
        }

        public virtual int YPos
        {
            get
            {
                if (ViewState["_yPos"] != null)
                {
                    return (int)ViewState["_yPos"];
                }
                else
                {
                    return 0;
                }
            }
            set { ViewState["_yPos"] = value; }
        }

        public virtual string NodeImageUrl
        {
            get
            {
                if (ViewState["_nodeImageUrl"] != null)
                {
                    return ViewState["_nodeImageUrl"].ToString();
                }
                else
                {
                    return "";
                }
            }
            set { ViewState["_nodeImageUrl"] = value; }
        }

        public virtual string DeleteNodeCssClass
        {
            get
            {
                if (ViewState["_deleteNodeCssClass"] == null)
                    return "";
                else
                    return ViewState["_deleteNodeCssClass"].ToString();
            }
            set { ViewState["_deleteNodeCssClass"] = value; }
        }

        public virtual string DetailsButtonText
        {
            get
            {
                if (ViewState["_detailsButtonText"] == null)
                    return "";
                else
                    return ViewState["_detailsButtonText"].ToString();
            }
            set { ViewState["_detailsButtonText"] = value; }
        }

        public virtual CallBackType LastCallbackType
        {
            get
            {
                if (ViewState["_lastCallBackType"] == null)
                    return CallBackType.Undefined;
                else
                    return (CallBackType)ViewState["_lastCallBackType"]; 
            }
            set { ViewState["_lastCallBackType"] = value; }
        }

        public virtual string NodeText
        {
            get
            {
                if (ViewState["_nodeText"] != null)
                {
                    return ViewState["_nodeText"].ToString();
                }
                else
                {
                    return "";
                }
            }
            set { ViewState["_nodeText"] = value; }
        }

        public virtual string NodeDescription
        {
            get
            {
                if (ViewState["_nodeDescription"] != null)
                {
                    return ViewState["_nodeDescription"].ToString();
                }
                else
                {
                    return "";
                }
            }
            set { ViewState["_nodeDescription"] = value; }
        }

        public virtual string NodeID
        {
            get
            {
                if (ViewState["_nodeID"] != null)
                    return ViewState["_nodeID"].ToString();
                else
                    return "";
            }
            set
            {
                ViewState["_nodeID"] = value;
            }
        }
      
        public virtual List<string> ParentOfIds
        {
            get
            {
                if (ViewState["_parentOfIds"] != null)
                    return (List<string>)ViewState["_parentOfIds"];
                else
                    return new List<string>();
            }
            set
            {
                ViewState["_parentOfIds"] = value;
            }
        }

        public virtual List<string> ChildOfIds
        {
            get
            {
                if (ViewState["_childOfIds"] != null)
                    return (List<string>)ViewState["_childOfIds"];
                else
                    return new List<string>();
            }
            set
            {
                ViewState["_childOfIds"] = value;
            }
        }

        public InternalDiagramNode(string nodeImageUrl, string serverText, string serverDescription, string serverID, int serverDBID, int xPos, int yPos, List<string> parentOfIds, List<string> childOfIds)
        {
            NodeUniqueIdentifier = serverDBID;
            NodeImageUrl = nodeImageUrl;
            NodeText = serverText;
            NodeDescription = serverDescription;
            NodeID = serverID;
            XPos = xPos;
            YPos = yPos;
            ParentOfIds = parentOfIds;
            ChildOfIds = childOfIds;                 
        }

        private LiteralControl serverText;
        private Image serverNode;
        private LiteralControl dScriptHolder;
        private HtmlButton detailsButton;

        protected override void CreateChildControls()
        {
            serverText = new LiteralControl(NodeText);
            
            serverNode = new Image();
            serverNode.ImageUrl = NodeImageUrl;

            string dScript = "var drag" + NodeID + " = document.getElementById(\"" + NodeID + "\"); Drag.init(drag" + NodeID + "); ";
            string _parentOfIds = "";
            string _parentLines = "";
            foreach (string dependentNode in ParentOfIds)
            {
                ((DiagramContainer)Parent).ZIndex--;
                _parentOfIds += dependentNode + " ";
                _parentLines += "<img id='" + NodeID + "ParentOf" + dependentNode + "' style='position:absolute' style='visibility:hidden;z-index:" + ((DiagramContainer)Parent).ZIndex.ToString() + ";'/>" +
                                "<img id='" + NodeID + "ParentOf" + dependentNode + "Arrow' style='position:absolute' style='visibility:hidden;z-index:" + (((DiagramContainer)Parent).ZIndex - 1).ToString() + ";'/>";
                ((DiagramContainer)Parent).ZIndex--;
            }
            _parentOfIds = _parentOfIds.Trim().Replace(" ", ",");

            string _childOfIds = "";
            string _childLines = "";
            foreach (string dependentNode in ChildOfIds)
            {
                ((DiagramContainer)Parent).ZIndex--;
                _childOfIds += dependentNode + " ";
                _childLines += "<img id='" + NodeID + "ChildOf" + dependentNode + "' style='position:absolute' style='visibility:hidden;z-index:" + ((DiagramContainer)Parent).ZIndex.ToString() + ";'/>" +
                               "<img id='" + NodeID + "ChildOf" + dependentNode + "Arrow' style='position:absolute' style='visibility:hidden;z-index:" + (((DiagramContainer)Parent).ZIndex - 1).ToString() + ";'/>";
                ((DiagramContainer)Parent).ZIndex--;
            }
            _childOfIds = _childOfIds.Trim().Replace(" ", ",");

            dScript += " drag" + NodeID + ".onDrag = function(x, y) { if ( (x * y) % 2 == 0) { drawParentLine('" + NodeID + "','" + _parentOfIds + "', x, y); drawChildLine('" + NodeID + "', '" + _childOfIds + "', x, y); } };  ";
            dScript += " drag" + NodeID + ".onDragEnd = function(x, y) { " + Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.NodeBeingRepositioned).ToString() + "' + x + '|' + y", "nodeSuccessfullyRepositioned", "null") + "; }; ";

            dScriptHolder = new LiteralControl("<script type=\"text/javascript\">" + dScript + "</script>" + _parentLines + _childLines);

            if (DetailsButtonText != "")
            {
                detailsButton = new HtmlButton();
                detailsButton.InnerText = DetailsButtonText;
                detailsButton.Attributes.Add("onclick", Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.NodeDetailsClicked).ToString() + "' + document.getElementById('" + NodeID + "MessageText').innerHTML", "nodeDetailsClicked", "null"));
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            string styling = "";
            if (this.BackColor != System.Drawing.Color.Empty && this.ForeColor != System.Drawing.Color.Empty && this.BorderColor != System.Drawing.Color.Empty)
                styling = " onmouseout = \"this.style.cursor='default'; this.style.backgroundColor='';this.style.borderRight='0px'; this.style.borderBottom='0px';\"; onmouseover=\"this.style.cursor='move'; this.style.backgroundColor='" + HexColorUtil.ColorToHex(ForeColor) + "';this.style.borderRight='1px inset " + HexColorUtil.ColorToHex(BorderColor) + "';this.style.borderBottom='1px inset " + HexColorUtil.ColorToHex(BorderColor) + "'\" ";

            double tWidth = this.Width.Value;
            double tHeight = this.Height.Value;
            if (DetailsButtonText != "")
            {
                //make room for button
                tWidth += 15;
                tHeight += 15;
            }

            //log for this node
            writer.Write("<div id='" + NodeID + "MessageText' style='position:absolute;display:none;'></div>");

            //absolute div container
            writer.Write("<div title=\"" + NodeDescription + "\" style=\"z-index:1;postion:absolute; left: " + XPos + "px; top:" + YPos + "px; width:" + tWidth.ToString() + "px;height:" + tHeight.ToString() + "px;\" id=\"" + NodeID + "\"" + styling + " ondblclick = \"" + Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.NodeDoubleClicked).ToString() + this.NodeUniqueIdentifier.ToString() + "'", "nodeDoubleClicked", "null") + "\">");
            
            //table containing layout
            writer.Write("<div style=\"position:relative;float:left;\">");
                serverNode.RenderControl(writer);
            writer.Write("</div>");

            if (DetailsButtonText != "" || DeleteNodeCssClass != "")
            {
                writer.Write("<div style=\"position:relative;float:right\">");

                    if (DetailsButtonText != "")
                        detailsButton.RenderControl(writer);

                    if (DeleteNodeCssClass != "")
                        writer.Write("<div style=\"position:relative;\" class=\"" + DeleteNodeCssClass + "\" onclick=\"" + Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.NodeDeleted).ToString() + "'", "nodeDeleteClicked", "null") + "\">&nbsp;</div>");

                writer.Write("</div>");
            }

            writer.Write("<div style='position:relative;clear:both;height:22px;background-color:" + HexColorUtil.ColorToHex(BackColor) + "'>");
                serverText.RenderControl(writer);
            writer.Write("</div>");

            writer.Write("</div>");
            
            dScriptHolder.RenderControl(writer);
        }

        public void RaiseCallbackEvent(String eventArgument)
        {
            string callbackString = eventArgument.Substring(1, eventArgument.Length - 1);
            switch (Convert.ToInt32(eventArgument.Substring(0,1)))
            {
                case (int)CallBackType.NodeBeingRepositioned:
                    LastCallbackType = CallBackType.NodeBeingRepositioned;
                    string[] splitter = callbackString.Split('|');
                    ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.Repositioned, new NodeRepositionEventArgs(NodeText, NodeUniqueIdentifier, Int32.Parse(splitter[0]), Int32.Parse(splitter[1])));
                    break;
                case (int)CallBackType.NodeDoubleClicked:
                    LastCallbackType = CallBackType.NodeDoubleClicked;
                    nodeDoubleClicked = new NodeDetailsEventArgs(NodeID, NodeText, NodeUniqueIdentifier, "");
                    ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.DoubleClicked, nodeDoubleClicked);
                    break;
                case (int)CallBackType.NodeDetailsClicked:
                    LastCallbackType = CallBackType.NodeDetailsClicked;
                    nodeClicked = new NodeDetailsEventArgs(NodeID, NodeText, NodeUniqueIdentifier, callbackString);
                     ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.DetailsClicked, nodeClicked);
                    break;
                case (int)CallBackType.NodeDeleted:
                    LastCallbackType = CallBackType.NodeDeleted;
                    nodeDeleteClicked = new NodeDetailsEventArgs(NodeID, NodeText, NodeUniqueIdentifier, callbackString);
                    ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.DeleteClicked, nodeDeleteClicked);
                    break;
            }
        }

        public string GetCallbackResult()
        {
            switch (LastCallbackType)
            {
                case CallBackType.NodeBeingRepositioned:
                    return "";
                case CallBackType.NodeDoubleClicked:
                    return nodeDoubleClicked.ModalDialogueHtmlToDisplay + "##" + nodeDoubleClicked.NavigateUrl + "##" + FormatUnit(nodeDoubleClicked.ModalDialogueWidth) + "##" + FormatUnit(nodeDoubleClicked.ModalDialogueHeight) + "##" + formatScripts(nodeDoubleClicked.ScriptsToExecuteOnModalWindowShown) + "##" + formatScripts(nodeDoubleClicked.ScriptsToExecuteOnModalWindowClose);
                case CallBackType.NodeDetailsClicked:
                    return nodeClicked.ModalDialogueHtmlToDisplay + "##" + nodeClicked.NavigateUrl + "##" + FormatUnit(nodeClicked.ModalDialogueWidth) + "##" + FormatUnit(nodeClicked.ModalDialogueHeight) + "##" + formatScripts(nodeClicked.ScriptsToExecuteOnModalWindowShown) + "##" + formatScripts(nodeClicked.ScriptsToExecuteOnModalWindowClose);
                default:
                    return "";
            }
        }

        private string formatScripts(List<string> allScripts)
        {
            string fScripts = "";
            foreach (string script in allScripts)
                fScripts += script + ";";

            if (fScripts.Length > 0)
                return fScripts.Substring(0, fScripts.Length - 1);
            else
                return "";
        }

        private string FormatUnit(Unit unitToFormat)
        {
            StringBuilder fu = new StringBuilder();
            fu.Append(unitToFormat.Value.ToString());

            switch (unitToFormat.Type)
            {
                case UnitType.Percentage:
                    fu.Append("%");
                    break;
                case UnitType.Pixel:
                    fu.Append("px");
                    break;
            }

            return fu.ToString();
        }
    }
}
